#include "hal_uart.h"
#include "hal_pow_meter.h"
#include "zqm_global.h"

#define POWM_UART_PKG_SIZE       24	    // 固定24字节
#define POWM_UART_RX_BUF_SIZE    (POWM_UART_PKG_SIZE * 3)
static uint8_t powm_uart_buf[POWM_UART_RX_BUF_SIZE];

static short vol_buf[POWM_SAMPLE_BUF_SZIE]; // 采样平均计算窗口
static short cur_buf[POWM_SAMPLE_BUF_SZIE];
static short pow_buf[POWM_SAMPLE_BUF_SZIE];

__HIGH_CODE
static uint8_t PowMGetChecksum(const uint8_t* data, unsigned int len)
{
    uint8_t s = 0;
    uint8_t* end = (uint8_t*)data + len;
    while (data < end)
        s += *(data++);
    return s;
}

// CSE7759B 4800bps 的波特率, 8 位数据，1 位偶校验，1 停止位, 每隔50ms自动将电压系数、电压周期、电流系数、电流周期、功率系数、功率周期、校准次数、CF 脉冲个数的数据包通过 TI 发送
// 数据包的具体格式为：包头(2*byte)→电压系数(3*byte)→电压周期(3*byte)→电流系数(3*byte)→电流周期(3*byte)→功率系数(3*byte)→功率周期(3*byte)→校准次数(1*byte)→CF脉冲个数(2*byte)→包尾(1*byte)。
// 共 24byte，4800bps 用时 54.912ms
__HIGH_CODE
void PowMeterUartRx_cb(uint8_t* data, uint16_t *plen)
{
#if 0
    static uint8_t pos = 0;
    uint16_t len = *plen;
    *plen = 0;
    // uint8_t* data = pkg->data;

    if(len != 24) return; // len must be fixed 24 bytes

    uint8_t start_f = data[POWM_I_HD];
    if(start_f == 0xaa) return; // chip not verified error
    if((start_f & 0xfd) > 0xf0) return; // 包头1=FxH且(包头1.bit0=1或包头1.bit2=1或包头1.bit3=1), Abnormal external circuit or chip damage

    uint8_t checksum = PowMGetChecksum(data+2, 21);
    if(checksum != data[POWM_I_SM]) return; // checksum error

    if(data[POWM_I_5A] != 0x5a) return; // must be fixed 0x5a

    // get voltage, current and active power value.
    uint8_t adj = data[POWM_I_FG];
    int vol, vol_t, cur, cur_t, pow, pow_t;
    if((adj & 0x40) == 0x40) { // 电压侦测周期完成
        vol_t = ZyGetValue_3B(data+POWM_I_VT);
        vol = (vol_t != 0) ? (int)ZyGetValue_3B(data+POWM_I_VK) / vol_t : 0;
    }
    else vol = 0;
    if((adj & 0x10) == 0x10 && (start_f & 0xf2) != 0xf2) { // 功率侦测周期完成，并且周期未超范围
        pow_t = ZyGetValue_3B(data+POWM_I_PT);
        pow = (pow_t != 0) ? (int)ZyGetValue_3B(data+POWM_I_PK) / pow_t : 0;
    }
    else pow = 0;
    if((adj & 0x10) == 0x10 && pow != 0) { // 电流侦测周期完成, 并且有功率值
        cur_t = ZyGetValue_3B(data+POWM_I_IT);
        cur = (cur_t != 0) ? (int)ZyGetValue_3B(data+POWM_I_IK) * 100 / cur_t * 10 : 0;    // 转mA, 先只乘100是怕溢出
    }
    else cur = 0;
    // 限制一下值有效
    if(cur <= POWM_CUR_MIN || pow <= POWM_POW_MIN) // 测量值低于量程, 算空载, 计0
        cur = pow = 0;
    // 值放入循环缓冲区
    vol_buf[pos] = (short)vol;
    cur_buf[pos] = (short)cur;
    pow_buf[pos] = (short)pow;
    if((++pos) >= POWM_SAMPLE_BUF_SZIE) pos = 0;
#endif
}

// init power meter device
void PowMeterInit(void)
{
#if (ZQ_FUNC_POW_METER == 1)
    UartInit(POWM_UART_PORT, 4800, powm_uart_buf, POWM_UART_RX_BUF_SIZE, PowMeterUartRx_cb);
#endif
}

// get current voltage, current and power value
void PowMeterGather(short *vol, short *cur, short *pow)
{
#if (ZQ_FUNC_POW_METER == 1)
    // UartRecv(POWM_UART_PORT, PowMeterUartRx_cb);
    *vol = ZyAverageShort(vol_buf, POWM_SAMPLE_BUF_SZIE);
    *cur = ZyAverageShort(cur_buf, POWM_SAMPLE_BUF_SZIE);
    *pow = ZyAverageShort(pow_buf, POWM_SAMPLE_BUF_SZIE);
    // 矫正
    *vol = (short)((int)(*vol) * (100 + m0_diag.ftm_vol_delta) / 100);
    *cur = (short)((int)(*cur) * (100 + m0_diag.ftm_cur_delta) / 100);
    *pow = (short)((int)(*pow) * (100 + m0_diag.ftm_pow_delta) / 100);
 
    static int x = 0;
    if((++x) % 100 == 0) {
        ZQLOG("power meter recv v=%d; c=%d; p=%d", *vol, *cur, *pow);
        // ZqHexDump("Read power meter data:", data, len);
        // ZQLOG("power meter recv cksum=%x, %x: vk=%x; vt=%x; - ik=%x; it=%x; - pk=%x; pt=%x; adj=%x", 
        //     checksum, data[POWM_I_SM], ZyGetValue_3B(data+POWM_I_VK), vol_t, ZyGetValue_3B(data+POWM_I_IK), cur_t, ZyGetValue_3B(data+POWM_I_PK), pow_t, data[POWM_I_FG];
    }
#endif
    return;
}